package com.ydj.app.service;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillWrapper;

import com.ydj.app.entity.CmsAccount;
import com.ydj.app.entity.ForecastQuestion;
import com.ydj.app.entity.ForecastResult;
import com.ydj.app.entity.WebUser;
import com.ydj.app.entity.dao.ForecastQuestionDao;
import com.ydj.app.entity.dao.ForecastResultDao;
import com.ydj.app.entity.dao.WebUserDao;
import com.ydj.app.entity.query.ForecastQuestionQuery;
import com.ydj.app.entity.query.ForecastResultQuery;
import com.ydj.app.entity.query.WebUserQuery;
import com.ydj.app.enumerate.ForecastQuestionCateEnum;
import com.ydj.app.enumerate.MemberLevelEnum;
import com.ydj.app.excel.ForecastResultListExcelDataToWrite;
import com.ydj.app.protocol.dto.ForecastQaItemDto;
import com.ydj.app.protocol.http.cms.CmsForecastExportListReq;
import com.ydj.app.protocol.http.cms.CmsForecastResultListReq;
import com.ydj.app.protocol.http.cms.CmsForecastResultListRes;
import com.ydj.app.protocol.http.web.WebForecastCommitReq;
import com.ydj.app.protocol.http.web.WebForecastCommitRes;
import com.ydj.app.protocol.http.web.WebForecastQuestionReq;
import com.ydj.app.protocol.http.web.WebForecastQuestionRes;
import com.ydj.app.third.ai.AiModelService;
import com.ydj.framework.exception.CommonException;
import com.ydj.framework.filter.ExtHttpServletResponse;
import com.ydj.framework.mysql.PageArgs;
import com.ydj.framework.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户相关服务
 */
@Slf4j
@Service
public class ForecastService {
    @Autowired
    private AiModelService aiModelService;
    @Autowired
    ForecastResultDao forecastDao;
    @Autowired
    ForecastQuestionDao forecastQuestionDao;
    @Autowired
    WebUserDao webUserDao;

    /**
     * 获取用户提交的预测、W
     */
    public CmsForecastResultListRes cmsResultList(CmsForecastResultListReq req, CmsAccount account) {
        PageArgs pageArgs = req.getPageArgs();
        List<ForecastResult> list = new ForecastResultQuery(forecastDao)
                .cate(req.getCate())
                .createTime(req.getStartTime(), req.getEndTime())
                .orderByCreateTimeDesc()
                .page(pageArgs);

        Map<Long, WebUser> webUserMap = new WebUserQuery(webUserDao)
                .ids(list.stream().map(forecast -> forecast.getWebUserId()).collect(Collectors.toSet()))
                .map();

        CmsForecastResultListRes res = new CmsForecastResultListRes(pageArgs);
        for (ForecastResult forecast : list) {
            WebUser user = webUserMap.get(forecast.getWebUserId());
            CmsForecastResultListRes.WebForecastListResItem item = new CmsForecastResultListRes.WebForecastListResItem()
                    .setId(forecast.getId())
                    .setMobileEmail(user != null ? user.getNickName() : "")
                    .setCate(forecast.getCate())
                    .setRate(forecast.getRate())
                    .setContact(forecast.getContact())
                    .setCreateTime(forecast.getCreateTime());
            res.addItem(item);
        }
        return res;

    }

    /**
     * 导出Excel
     */
    public void cmsExportExcel(ExtHttpServletResponse response, CmsForecastExportListReq req, CmsAccount account) throws IOException {
        // 1. 准备数据
        List<ForecastResult> list = new ForecastResultQuery(forecastDao)
                .cate(req.getCate())
                .createTime(req.getStartTime(), req.getEndTime())
                .list();
        Map<Long, WebUser> webUserMap = new WebUserQuery(webUserDao)
                .ids(list.stream().map(forecast -> forecast.getWebUserId()).collect(Collectors.toSet()))
                .map();
        List<ForecastResultListExcelDataToWrite> rowData = new LinkedList<>();
        for (ForecastResult forecast : list) {
            WebUser user = webUserMap.get(forecast.getWebUserId());
            // 问答的数据结构
            Map<String, String> questionAnswerMap = new LinkedHashMap<>();
            for(ForecastQaItemDto qaItem : forecast.getQaList()) {
                questionAnswerMap.put(qaItem.getExcelQuestion(), qaItem.getExcelAnswer());
            }

            ForecastResultListExcelDataToWrite row = new ForecastResultListExcelDataToWrite()
                .setSeq(0)
                .setCreateTime(DateUtils.dateToString(forecast.getCreateTime()))
                .setNickName(user != null ? user.getNickName() : "")
                .setCate(forecast.getCate().getDesc())
                .setRate(forecast.getRate() + "%")
                .setContact(forecast.getContact())
                .setQuestionAnswerMap(questionAnswerMap);

            rowData.add(row);
        }

        // 2. 收集所有动态问题（确保顺序一致）
        LinkedHashSet<String> allQuestions = new LinkedHashSet<>();
        rowData.forEach(d -> allQuestions.addAll(d.getQuestionAnswerMap().keySet()));

        // 3. 构建表头 Map
        Map<String, String> headerMap = new HashMap<>();
        int col = 1;
        for (String q : allQuestions) {
            headerMap.put("question_" + (col++), q);
        }

        // 4. 构建数据 List<Map>
        List<Map<String, Object>> fillData = new ArrayList<>();
        for (ForecastResultListExcelDataToWrite dto : rowData) {
            Map<String, Object> row = new HashMap<>();
            row.put("seq", dto.getSeq());
            row.put("createTime", dto.getCreateTime());
            row.put("nickName", dto.getNickName());
            row.put("cate", dto.getCate());
            row.put("rate", dto.getRate());
            row.put("contact", dto.getContact());

            // 把动态答案按列顺序放进去
            col = 1;
            for (String q : allQuestions) {
                row.put("answer_" + (col++), dto.getQuestionAnswerMap().get(q));
            }
            fillData.add(row);
        }

        // 5. 真正写入
        response.configEasyExcelHeader("预测结果.xlsx");
        String templateResPath = "template.excel/ForecastResultlListTemplate.xlsx";
        Resource resource = new ClassPathResource(templateResPath);
        try (InputStream inputStream = resource.getInputStream()) {
            ExcelWriter writer = EasyExcel.write(response.getOutputStream())
                    .withTemplate(inputStream)
                    .build();

            WriteSheet sheet = EasyExcel.writerSheet().build();

            // 5-1 填充表头（横向扩展）
            writer.fill(new FillWrapper("header", Collections.singletonList(headerMap)), sheet);

            // 5-2 填充数据（自动横向+纵向扩展）
            writer.fill(new FillWrapper("data", fillData), sheet);

            writer.finish();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取问题
     */
    public WebForecastQuestionRes webQuestion(WebForecastQuestionReq req, WebUser webUser) throws CommonException {
        ForecastQuestion question = new ForecastQuestionQuery(forecastQuestionDao)
                .cate(req.getCate())
                .single();
        CommonException.throwExceptionIfNull(question, "还没有配置该预测类型");

        return new WebForecastQuestionRes()
                .setList(question.getQuestionList());
    }

    /**
     * 提交问题
     */
    @Transactional(rollbackOn = Exception.class)
    public WebForecastCommitRes webCommit(WebForecastCommitReq req, WebUser webUser) throws CommonException {
        // 免费会员会被限制次数的
        if (webUser.getLevel() == MemberLevelEnum.非会员) {
            if (req.getCate() == ForecastQuestionCateEnum.个人) {
                if (webUser.getFreeForecastPersonalCount() <= 0) {
                    return new WebForecastCommitRes()
                            .setOverFreeTime(true)
                            .setFreeForecastPersonalCount(webUser.getFreeForecastPersonalCount())
                            .setFreeForecastCompanyCount(webUser.getFreeForecastCompanyCount());
                } else if (webUser.getFreeForecastCompanyCount() <= 0) {
                    return new WebForecastCommitRes()
                            .setOverFreeTime(true)
                            .setFreeForecastPersonalCount(webUser.getFreeForecastPersonalCount())
                            .setFreeForecastCompanyCount(webUser.getFreeForecastCompanyCount());
                }
            }
        }

        // 发送到Deepseek获取答案
        AiModelService.AiForecastResult aiForecastResult = aiModelService.getForecastResultByYuanQi(req.getQaList(), webUser.getId());
        CommonException.throwExceptionIfNull(aiForecastResult, "预测异常，请再试一次");
        int rate = aiForecastResult.getRate();
        String result = aiForecastResult.getResult();

        // 保存结果
        ForecastResult forecastResult = new ForecastResult()
                .setWebUserId(webUser.getId())
                .setCate(req.getCate())
                .setContact(req.getContact())
                .setQaList(req.getQaList())
                .setRate(rate)
                .setResult(result);
        forecastDao.saveOrUpdate(forecastResult);

        // 扣减次数
        if (webUser.getLevel() == MemberLevelEnum.非会员) {
            if (req.getCate() == ForecastQuestionCateEnum.个人) {
                webUser.incFreeForecastPersonalCount(-1);
            } else if (req.getCate() == ForecastQuestionCateEnum.企业) {
                webUser.incFreeForecastCompanyCount(-1);
            }
            webUserDao.saveOrUpdate(webUser);
        }

        // 返回结果
        return new WebForecastCommitRes()
                .setOverFreeTime(false)
                .setFreeForecastCompanyCount(webUser.getFreeForecastCompanyCount())
                .setFreeForecastPersonalCount(webUser.getFreeForecastPersonalCount())
                .setRate(rate)
                .setResult(result);
    }


}